package com.edu.tool.bc;

import com.google.common.collect.HashMultimap;

import java.util.*;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

public class SysBcDef {
    public String baseBean ="";

    public String bcName ;

    public Map<String,String> bean2Table = new HashMap<>();

    public Map<String,SysField> mfields = new HashMap<>();
    public List<SysJoinDef>     joindefs= new ArrayList<>();

    public List<String> mGroupFields = new ArrayList<>();

    public HashMultimap<String, QuerySpec> fieldQuerySpec =  HashMultimap.create();



    public   Map<String, List<String>>     beanDepson       = new HashMap<>();
    public   Map<String, List<SysJoinDef>> toBean2JoinDef   = new HashMap<>();
    public   Map<String, List<SysJoinDef>> fromBean2JoinDef = new HashMap<>();

    //public static Map<String,Class> beanName2Class       = new HashMap<String,Class>();
    //public static Map<String,Class> beanName2MapperClass = new HashMap<String,Class>();
    public static String sysCols[] = {"id","create_time","create_by","update_time","update_by"};


    public static Map<String,SysLinkDef>      linkdefs    = new HashMap<>();
    public static Map<String,SysMVLDef>       mvls        = new HashMap<>();
    public static Map<String,SysPickListDef>  pickListMap = new HashMap<>();
    static {
        pickListMap.put("",new SysPickListDef("PickList Internal Division","Internal Division","",""));
    }


    public static ConcurrentHashMap<String, FutureTask<SysBcDef>> bcDefConcurrentHashMap= new ConcurrentHashMap<>();


    public static SysBcDef getBc(String name)  {
        FutureTask<SysBcDef> sysBcDefTask = bcDefConcurrentHashMap.get(name);
        try {
            if (sysBcDefTask == null) {
                Callable<SysBcDef> callable = new Callable<SysBcDef>() {
                    @Override
                    public SysBcDef call() throws Exception {
                        return createBcDef(name);
                    }
                };

                FutureTask<SysBcDef> newTask = new FutureTask<SysBcDef>(callable);
                sysBcDefTask = bcDefConcurrentHashMap.putIfAbsent(name, newTask);
                if (sysBcDefTask == null) {
                    sysBcDefTask = newTask;
                    sysBcDefTask.run();
                }
                return sysBcDefTask.get();
            } else {
                return sysBcDefTask.get();
            }
        }catch(ExecutionException ee){
           return null;
        }
        catch(InterruptedException ie){
            return null;
        }
    }

    private static SysBcDef createBcDef(String name) {
        SysBcDef sysBcDef = new SysBcDef();
        if (name.equalsIgnoreCase("Contact")) {
            sysBcDef.bcName = "Contact";
            sysBcDef.baseBean = "SysParty";

            //beanName2Class.put("SysParty", com.edu.tool.bean.user.SysParty.class);
            //beanName2Class.put("SysContact", com.edu.tool.bean.user.SysContact.class);

            //beanName2MapperClass.put("SysParty", SysPartyMapper.class);
            //beanName2MapperClass.put("SysContact", SysContactMapper.class);

            sysBcDef.mfields.put("id", new SysField("id", false, ""));
            sysBcDef.mfields.put("contact name", new SysField("SysContact.name", false, ""));
            sysBcDef.mfields.put("first name", new SysField("SysContact.firstName", false, ""));

            sysBcDef.joindefs.add(new SysJoinDef("SysParty",
                    "SysContact",
                    "id",
                    "par_row_id", true));
            sysBcDef.bean2Table.put("SysParty", "s_party");
            sysBcDef.bean2Table.put("SysContact", "s_contact");



        } else if (name.equalsIgnoreCase("Organization")) {
            sysBcDef.bcName   = "Organization";

            sysBcDef.baseBean = "SysParty";

            sysBcDef.bean2Table.put("SysParty", "s_party");
            sysBcDef.bean2Table.put("SysOrganization", "s_org_ext");
            sysBcDef.bean2Table.put("SysParOrganization", "s_org_ext");
            sysBcDef.bean2Table.put("SysParDivision", "s_org_ext");
            sysBcDef.bean2Table.put("SysBU", "s_bu");
            sysBcDef.bean2Table.put("SysDynHrchy", "s_dyn_hrchy");
            sysBcDef.bean2Table.put("SysPartnerMgr", "s_postn");

            //beanName2Class.put("SysParty", com.edu.tool.bean.user.SysParty.class);
            //beanName2Class.put("SysContact", com.edu.tool.bean.user.SysContact.class);

            //beanName2MapperClass.put("SysParty", SysPartyMapper.class);
            //beanName2MapperClass.put("SysContact", SysContactMapper.class);

            //sysBcDef.fields.put("id", "id");
            //sysBcDef.fields.put("Party Name", "name");
            sysBcDef.mfields.put("id", new SysField("id", false, ""));
            sysBcDef.mfields.put("Party Name", new SysField("name", false, ""));

            sysBcDef.mfields.put("Parent Organization Id", new SysField("par_party_id", false, ""));

            //sysBcDef.fields.put("Party Hierarchy Root Flag", "name");
            sysBcDef.mfields.put("Name", new SysField("SysOrganization.name", false, ""));
            sysBcDef.mfields.put("Parent Organization Name", new SysField("SysParOrganization.name", false, ""));


            sysBcDef.mfields.put("Parent Division Id", new SysField("SysOrganization.par_divn_id", false, ""));
            sysBcDef.mfields.put("Currency Code", new SysField("SysOrganization.base_curcy_dc", false, ""));
            sysBcDef.mfields.put("Organization Id", new SysField("SysOrganization.par_bu_id", false, ""));
            sysBcDef.mfields.put("Internal Org Flag", new SysField("SysOrganization.int_org_flg", false, ""));
            sysBcDef.mfields.put("Partner Flag", new SysField("SysOrganization.prtnr_flg", false, ""));
            sysBcDef.mfields.put("Partner Manager Position Id", new SysField("SysOrganization.pr_mgr_postn_id", false, ""));
            sysBcDef.mfields.put("Type", new SysField("SysOrganization.divn_type_cd", false, ""));
            sysBcDef.mfields.put("Partner Manager Position", new SysField("SysPartnerMgr.name", false, ""));
            sysBcDef.mfields.put("Organization Flag", new SysField("SysBU.bu_flg", false, ""));
            sysBcDef.mfields.put("Annual Review EndOffset", new SysField("SysBU.annlrvw_endt_offset", false, ""));
            sysBcDef.mfields.put("Annual Review StartOffset", new SysField("SysBU.annlrvw_stdt_offset", false, ""));
            sysBcDef.mfields.put("Current Review Period", new SysField("SysBU.curr_prd_rvw_name", false, ""));
            sysBcDef.mfields.put("Current Objectives Period", new SysField("SysBU.curr_prd_obj_name", false, ""));

            sysBcDef.mfields.put("Dynamic HierarchyId", new SysField("SysBU.dyn_hrchy_id", false, ""));
            sysBcDef.mfields.put("Dynamic HierarchyName", new SysField("SysDynHrchy.name", false, ""));


            sysBcDef.joindefs.add(new SysJoinDef("SysParty",
                    "SysOrganization",
                    "id",
                    "par_row_id", true));

            sysBcDef.joindefs.add(new SysJoinDef("SysOrganization",
                    "SysParDivision",
                    "par_divn_id",
                    "id", false));

            sysBcDef.joindefs.add(new SysJoinDef("SysOrganization",
                    "SysPartnerMgr",
                    "pr_mgr_postn_id",
                    "par_row_id", false));

            sysBcDef.joindefs.add(new SysJoinDef("SysParty",
                    "SysParOrganization",
                    "par_party_id",
                    "par_row_id", false));

            sysBcDef.joindefs.add(new SysJoinDef("SysParty",
                    "SysBU",
                    "id",
                    "par_row_id", true)
            );

            sysBcDef.joindefs.add(new SysJoinDef("SysBU",
                    "SysDynHrchy",
                    "dyn_hrchy_id",
                    "id", false)
            );


        } else if (name.equalsIgnoreCase("Position")) {
            sysBcDef.bcName = "Position";

            sysBcDef.baseBean = "SysParty";

            //Give an alias(Using a bean name) to table
            sysBcDef.bean2Table.put("SysParty", "s_party");
            sysBcDef.bean2Table.put("SysPosition", "s_postn");
            sysBcDef.bean2Table.put("SysParPosition", "s_postn");
            sysBcDef.bean2Table.put("SysOrgInt", "s_org_ext");
            sysBcDef.bean2Table.put("SysOrgBU", "s_bu");

            //sysBcDef.fields.put("id", "id");
            //sysBcDef.fields.put("Party Name", "name");

            sysBcDef.mfields.put("id", new SysField("id", false, ""));
            sysBcDef.mfields.put("Party Name", new SysField("name", false, ""));

            //join fields from extension table
            sysBcDef.mfields.put("Name", new SysField("SysPosition.name", false, ""));
            sysBcDef.mfields.put("Position Type", new SysField("SysPosition.postn_type_cd", false, ""));
            sysBcDef.mfields.put("Primary Employee Id", new SysField("SysPosition.pr_emp_id", false, ""));
            sysBcDef.mfields.put("Parent Position Id", new SysField("SysPosition.par_party_id", false, ""));

            sysBcDef.mfields.put("Organization Id", new SysField("SysPosition.bu_id", false, ""));

            sysBcDef.mfields.put("Description", new SysField("SysPosition.desc_text", false, ""));

            List<SysPickMap> pickMap = new LinkedList<>() ;
            pickMap.add(new SysPickMap("Name","Division"));
            pickMap.add(new SysPickMap("Id","Division Id"));
            pickMap.add(new SysPickMap("Organization Id","Organization Id"));

            sysBcDef.mfields.put("Division Id", new SysField("SysPosition.ou_id", false, "","PickList Internal Division",pickMap));

            sysBcDef.mfields.put("Integration Id", new SysField("SysPosition.ou_id", false, ""));

            sysBcDef.mfields.put("Compensatable", new SysField("SysPosition.compensatable_flg", false, ""));

            sysBcDef.mfields.put("Compensation Plan Rollout Level", new SysField("SysPosition.cp_plan_lvl_num", false, ""));
            sysBcDef.mfields.put("Position Id", new SysField("SysPosition.id", false, ""));

            sysBcDef.mfields.put("Compensation Currency Code", new SysField("SysPosition.cmpns_curcy_cd", false, ""));
            sysBcDef.mfields.put("Primary Territory Id", new SysField("SysPosition.pr_terr_id", false, ""));

            sysBcDef.mfields.put("Billing Product Id", new SysField("SysPosition.bl_prod_id", false, ""));

            //join fields not from extension table
            sysBcDef.mfields.put("Parent Position Name", new SysField("SysParPosition.name", false, ""));

            pickMap = new LinkedList<>() ;
            pickMap.add(new SysPickMap("Currency Code","Compensation Currency Code"));
            pickMap.add(new SysPickMap("Name","Division"));
            pickMap.add(new SysPickMap("Id","Division Id"));
            pickMap.add(new SysPickMap("Organization","Organization"));
            pickMap.add(new SysPickMap("Organization Id","Organization Id"));
            sysBcDef.mfields.put("Division", new SysField("SysOrgInt.name", false, "","PickList Internal Division",pickMap));

            sysBcDef.mfields.put("Division BU Id", new SysField("SysOrgInt.bu_id", false, ""));
            sysBcDef.mfields.put("Division Currency Code", new SysField("SysOrgInt.base_curcy_cd", false, ""));

            pickMap = new LinkedList<>() ;
            pickMap.add(new SysPickMap("Integration Id","Division Integration Id"));
            pickMap.add(new SysPickMap("Name","Division"));
            pickMap.add(new SysPickMap("Id","Division Id"));
            pickMap.add(new SysPickMap("Organization","Organization"));
            pickMap.add(new SysPickMap("Organization Id","Organization Id"));

            sysBcDef.mfields.put("Division Integration Id", new SysField("SysOrgInt.integration_id", false, "","PickList Internal Division",pickMap));
            sysBcDef.mfields.put("Division Location", new SysField("SysOrgInt.loc", false, ""));
            sysBcDef.mfields.put("Division Manager Id", new SysField("SysOrgInt.pr_mgr_postn_id", false, ""));

            pickMap = new LinkedList<>() ;

            pickMap.add(new SysPickMap("Organization","Organization"));
            pickMap.add(new SysPickMap("Organization Id","Organization Id"));

            sysBcDef.mfields.put("Organization", new SysField("SysOrgBU.name", false, "","PickList Internal Division",pickMap));
            sysBcDef.mfields.put("Billing Product", new SysField("SysInternProd.name", false, ""));


//                SysPickMap divisionPickMap = new SysPickMap();
//                divisionPickMap.pickBCName = "Division";
//                divisionPickMap.maps.put("Name","Division");
//                divisionPickMap.maps.put("Id","Division Id");
//                divisionPickMap.maps.put("Organization","Organization");
//                divisionPickMap.maps.put("Organization Id","Organization Id");
//                divisionPickMap.maps.put("Currency Code","Compensation Currency Code");

            //multi value fields
            sysBcDef.mfields.put("Last Name", new SysField("Last Name", true, "Employee"));
            sysBcDef.mfields.put("First Name", new SysField("First Name", true, "Employee"));
            sysBcDef.mfields.put("Job Title", new SysField("Job Title", true, "Employee"));
            sysBcDef.mfields.put("Start Date", new SysField("Start Date", true, "Employee"));
            sysBcDef.mfields.put("End Date", new SysField("End Date", true, "Employee"));

            sysBcDef.mfields.put("Territory", new SysField("Name", true, "Territory"));


            sysBcDef.joindefs.add(new SysJoinDef("SysParty",
                    "SysPosition",
                    "id",
                    "par_row_id", true)
            );

            sysBcDef.joindefs.add(new SysJoinDef("SysParty",
                    "SysParPosition",
                    "par_party_id",
                    "par_row_id", true)
            );

            sysBcDef.joindefs.add(new SysJoinDef("SysPosition",
                    "SysOrgInt",
                    "bu_id",
                    "par_row_id", true)
            );

            sysBcDef.joindefs.add(new SysJoinDef("SysPosition",
                    "SysOrgBU",
                    "bu_id",
                    "par_row_id", true)
            );

            sysBcDef.joindefs.add(new SysJoinDef("SysPosition",
                    "SysInternProd",
                    "bl_prod_id",
                    "row_id", true)
            );

            //links to other bcs
            sysBcDef.mvls.put("Employee", new SysMVLDef("Employee", "Employee", "Primary Employee Id", "Position/Employee"));
            sysBcDef.mvls.put("Territory", new SysMVLDef("Territory", "Assignment Group", "Primary Territory Id", "Position/Assignment Group"));

            sysBcDef.linkdefs.put("Position/Employee", new SysLinkDef("Position",
                    "Employee",
                    "party_id",
                    "person_id",
                    "s_party_per",
                    "Primary Employee Id",
                    "",
                    ""
            ));

            sysBcDef.linkdefs.put("Position/Assignment Group", new SysLinkDef("Position",
                    "Assignment Group",
                    "postn_id",
                    "asgn_grp_id",
                    "s_asgn_grp_postn",
                    "Primary Territory Id",
                    "",
                    ""
            ));
        } else if (name.equalsIgnoreCase("Employee")) {
            sysBcDef.bcName = "Employee";

            sysBcDef.baseBean = "SysParty";

            //Give an alias(Using a bean name) to table
            sysBcDef.bean2Table.put("SysParty", "s_party");
            sysBcDef.bean2Table.put("SysContact", "s_contact");
            sysBcDef.bean2Table.put("SysPartyPer", "s_party_per");

            //sysBcDef.fields.put("id", "id");
            //sysBcDef.fields.put("Party Name", "name");
            sysBcDef.mfields.put("id", new SysField("id", false, ""));
            sysBcDef.mfields.put("PartyName", new SysField("name", false, ""));


            //join fields from extension table
            sysBcDef.mfields.put("Last Name", new SysField("SysContact.last_name", false, ""));
            sysBcDef.mfields.put("First Name", new SysField("SysContact.fst_name", false, ""));
            sysBcDef.mfields.put("Job Title", new SysField("SysContact.job_title", false, ""));
            sysBcDef.mfields.put("Start Date", new SysField("SysContact.start_dt", false, ""));
            sysBcDef.mfields.put("End Date", new SysField("SysContact.end_dt", false, ""));

            //join fields not from extension table
            sysBcDef.mfields.put("Parent Position Name", new SysField("SysParPosition.name", false, ""));


//                SysPickMap divisionPickMap = new SysPickMap();
//                divisionPickMap.pickBCName = "Division";
//                divisionPickMap.maps.put("Name","Division");
//                divisionPickMap.maps.put("Id","Division Id");
//                divisionPickMap.maps.put("Organization","Organization");
//                divisionPickMap.maps.put("Organization Id","Organization Id");
//                divisionPickMap.maps.put("Currency Code","Compensation Currency Code");

            //multi value fields
            //sysBcDef.mfields.put("Last Name",new SysField("Last Name",true,"Employee"));

            //joins
            sysBcDef.joindefs.add(new SysJoinDef("SysParty",
                    "SysContact",
                    "id",
                    "par_row_id", true)
            );

            sysBcDef.joindefs.add(new SysJoinDef("SysParty",
                    "SysPartyPer",
                    "id",
                    "party_id", true)
            );

            //links to other bcs
//                sysBcDef.linkdefs.put("Employee",new SysLinkDef("Position",
//                        "Employee",
//                        "party_id",
//                        "person_id",
//                        "s_party_per",
//                        "Primary Employee Id"
//                ));


        } else if (name.equalsIgnoreCase("Territory")) {

            sysBcDef.bcName = "Territory";

            sysBcDef.baseBean = "SysTerr";

            //Give an alias(Using a bean name) to table
            sysBcDef.bean2Table.put("SysTerr", "s_terr");


            sysBcDef.mfields.put("id", new SysField("id", false, ""));
            sysBcDef.mfields.put("Name", new SysField("name", false, ""));


            //join fields from extension table
            //sysBcDef.mfields.put("Last Name",new SysField("SysContact.last_name",false,""));

            //join fields not from extension table
            //sysBcDef.mfields.put("Parent Position Name",new SysField("SysParPosition.name",false,""));


//                SysPickMap divisionPickMap = new SysPickMap();
//                divisionPickMap.pickBCName = "Division";
//                divisionPickMap.maps.put("Name","Division");
//                divisionPickMap.maps.put("Id","Division Id");
//                divisionPickMap.maps.put("Organization","Organization");
//                divisionPickMap.maps.put("Organization Id","Organization Id");
//                divisionPickMap.maps.put("Currency Code","Compensation Currency Code");

            //multi value fields
            //sysBcDef.mfields.put("Last Name",new SysField("Last Name",true,"Employee"));

            //joins
//                sysBcDef.joindefs.add(new SysJoinDef("SysParty",
//                        "SysContact",
//                        "id",
//                        "par_row_id",true)
//                );


            //links to other bcs
//                sysBcDef.linkdefs.put("Employee",new SysLinkDef("Position",
//                        "Employee",
//                        "party_id",
//                        "person_id",
//                        "s_party_per",
//                        "Primary Employee Id"
//                ));

        }else if (name.equalsIgnoreCase("Internal Division")) {

            sysBcDef.bcName = "Internal Division";

            sysBcDef.baseBean = "SysParty";

            //Give an alias(Using a bean name) to table
            sysBcDef.bean2Table.put("SysParty", "s_party");
            sysBcDef.bean2Table.put("SysOrganization", "s_org_ext");
            sysBcDef.bean2Table.put("SysParOrganization", "s_org_ext");
            sysBcDef.bean2Table.put("SysParDivision", "s_org_ext");
            sysBcDef.bean2Table.put("SysBU", "s_bu");

            //sysBcDef.fields.put("Party Name", "name");
            sysBcDef.mfields.put("id", new SysField("id", false, ""));
            sysBcDef.mfields.put("Party Name", new SysField("name", false, ""));

            sysBcDef.mfields.put("Parent Organization Id", new SysField("par_party_id", false, ""));


            sysBcDef.mfields.put("Name", new SysField("SysOrganization.name", false, ""));
            sysBcDef.mfields.put("Parent Organization Name", new SysField("SysParOrganization.name", false, ""));


            sysBcDef.mfields.put("Parent Division Id", new SysField("SysOrganization.par_divn_id", false, ""));
            sysBcDef.mfields.put("Currency Code", new SysField("SysOrganization.base_curcy_dc", false, ""));
            sysBcDef.mfields.put("Organization Id", new SysField("SysOrganization.par_bu_id", false, ""));
            sysBcDef.mfields.put("Internal Org Flag", new SysField("SysOrganization.int_org_flg", false, ""));

            //join fields not from extension table
            sysBcDef.mfields.put("Parent Position Name", new SysField("SysParPosition.name", false, ""));


        }
        calBeanDependency(sysBcDef);
        calFieldReadOnly(sysBcDef);
        return sysBcDef;
    }

    private static  void calBeanDependency(SysBcDef bcdef) {
        List<SysJoinDef> joindefs                      = bcdef.joindefs;
        Map<String, List<String>>     beanDepson       = bcdef.beanDepson;
        Map<String, List<SysJoinDef>> toBean2JoinDef   = bcdef.toBean2JoinDef;
        Map<String, List<SysJoinDef>> fromBean2JoinDef = bcdef.fromBean2JoinDef;

        for (int i = 0; i < joindefs.size(); i++) {
            SysJoinDef joinDef = joindefs.get(i);
            String childBean = joinDef.getChildBean();
            String parentBean = joinDef.getParentBean();

            List<String> lstBeans = beanDepson.get(parentBean);

            if (lstBeans != null) {
                lstBeans.add(childBean);
            } else {
                lstBeans = new ArrayList<>();
                lstBeans.add(childBean);
            }
            beanDepson.put(parentBean, lstBeans);

            List<SysJoinDef> lstJoinDefs = toBean2JoinDef.get(childBean);
            if (lstJoinDefs != null) {
                lstJoinDefs.add(joinDef);
            } else {
                lstJoinDefs = new ArrayList<>();
                lstJoinDefs.add(joinDef);
            }
            toBean2JoinDef.put(childBean, lstJoinDefs);


            List<SysJoinDef> fromLstJoinDefs = fromBean2JoinDef.get(parentBean);
            if(fromLstJoinDefs != null){
                fromLstJoinDefs.add(joinDef);
            }else{
                fromLstJoinDefs = new ArrayList<>();
                fromLstJoinDefs.add(joinDef);
            }
            fromBean2JoinDef.put(parentBean,fromLstJoinDefs);
        }

    }

    private static void calFieldReadOnly(SysBcDef bcdef) {
        Map<String, SysField>         fielddefs        =  bcdef.mfields;
        Map<String, List<SysJoinDef>> toBean2JoinDef   = bcdef.toBean2JoinDef;
        for (Map.Entry<String,SysField> entry : fielddefs.entrySet()) {

            SysField beanField = (SysField) entry.getValue();
            if( beanField.isMVF() )
            {
                beanField.setReadOnly(true);
                continue;
            }
            String bfarray[] = beanField.getFullField().split("\\.");
            if (bfarray.length == 1) {
                beanField.setReadOnly(false);
            }
            else{
                String beanName = bfarray[0];
                List<SysJoinDef> joinDefs = toBean2JoinDef.get(beanName);
                SysJoinDef joindef = joinDefs.get(0);
                if(joindef.getExtension()){

                    beanField.setReadOnly(false);
                }
                else
                {
                    beanField.setReadOnly(true);
                }
            }
        }
    }
}
